import * as THREE from 'three';
import getGLTFLoader from 'tools/loaders/getGLTFLoader';
import State from '../State';
import Element, { GLTF } from '../State/Element';
import { message } from 'antd';

export default async function recover(s: State, data: any) {
    
    // 清空舞台
    s.elementMap.forEach(e => { e.getObject3D()?.removeFromParent() });
    s.selectedElementUuid = undefined;
    s.elementMap = new Map();
    s.version++;

    // 摄像头
    if (s.camera && s.controls) {
        s.camera.position.set(
            data.camera.position.x,
            data.camera.position.y,
            data.camera.position.z,
        )
        s.controls.target = new THREE.Vector3(
            data.camera.target.x,
            data.camera.target.y,
            data.camera.target.z,
        )
    }

    // 地面
    if (s.floor instanceof THREE.Mesh) {
        const geometry = new THREE.PlaneGeometry(data.floor.width, data.floor.width);
        const material = new THREE.MeshPhongMaterial({ color: new THREE.Color(data.floor.color), side: THREE.DoubleSide });
        s.floor.geometry = geometry;
        s.floor.material = material;
        s.scene?.add(s.floor);
    }

    // 添加原件
    for (let i = 0; i < data.items.length; i++) {
        const e = data.items[i];
        switch (e.type) {
            case 'light':
                createLight(s, e);
                break;
            case 'gltf':
                await createGltf(s, e);
                break;
            case 'tag':
                createTag(s, e);
                break;
        }
    }

    // 设置目标
    await data.items.forEach(async e => {
        if (!e.object3D.target) return;
        try {
            const o3d = s.elementMap.get(e.uuid)?.getObject3D() as any;
            o3d.target = s.elementMap.get(e.object3D.target)?.getObject3D();
        } catch (error) {
            console.error(error);
        }
    })
}

/** 创建 gltf */
async function createGltf(s: State, e: any) {
    try {
        const gltf = new GLTF(await getGLTFLoader(e.object3D.path), e.object3D.path);
        gltf.scene.scene.visible = e.object3D.visible;

        gltf.scene.scene.castShadow = e.object3D.castShadow;
        gltf.scene.scene.traverse(child => {
            child.castShadow = e.object3D.castShadow;
        })

        gltf.scene.scene.receiveShadow = e.object3D.receiveShadow;
        gltf.scene.scene.traverse(child => {
            child.receiveShadow = e.object3D.receiveShadow;
        })

        gltf.scene.scene.position.set(
            e.object3D.position.x,
            e.object3D.position.y,
            e.object3D.position.z,
        );

        gltf.scene.scene.rotation.set(
            e.object3D.rotation.x,
            e.object3D.rotation.y,
            e.object3D.rotation.z,
        );

        gltf.scene.scene.scale.set(
            e.object3D.scale.x,
            e.object3D.scale.y,
            e.object3D.scale.z,
        );

        gltf.play(e.object3D.animationName)
        addScene(s, e, new Element('gltf', e.uuid, gltf));

    } catch (error) {
        message.error('模型加载失败');
        console.error(error)
    }
}

/** 创建 标记 */
function createTag(s: State, e: any) {
    const geometry = new THREE.SphereGeometry(0.1);
    const material = new THREE.MeshBasicMaterial({ color: 0xffffff });
    const sphere = new THREE.Mesh(geometry, material);
    sphere.visible = s.model === 'edit';
    sphere.position.set(
        e.object3D.position.x,
        e.object3D.position.y,
        e.object3D.position.z,
    );

    addScene(s, e, new Element('tag', sphere.uuid, sphere));
}

/** 创建光 */
function createLight(s: State, e: any) {
    switch (e.object3D.lightType) {
        case 'AmbientLight':
            ambientLight(s, e);
            break;
        case 'SpotLight':
            spotLight(s, e);
            break;
        case 'DirectionalLight':
            directionalLight(s, e);
            break;
        case 'PointLight':
            pointLight(s, e);
            break;
        case 'RectAreaLight':
            rectAreaLight(s, e);
            break;
        default:
            break;
    }
}

/** 环境光 */
function ambientLight(s: State, e: any) {
    const light = new THREE.AmbientLight(e.object3D.color);
    light.visible = e.object3D.visible;
    light.intensity = e.object3D.intensity;
    light.position.set(
        e.object3D.position.x,
        e.object3D.position.y,
        e.object3D.position.z,
    );

    addScene(s, e, new Element('light', light.uuid, light));
}

/** 聚光灯 */
function spotLight(s: State, e: any) {

    const light = new THREE.SpotLight(e.object3D.color);
    light.shadow.camera.far = 1000;
    light.visible = e.object3D.visible;
    light.shadow.bias = e.object3D.bias;
    light.intensity = e.object3D.intensity;
    light.angle = e.object3D.angle;
    light.decay = e.object3D.decay;
    light.power = e.object3D.power;
    light.distance = e.object3D.distance;
    light.castShadow = e.object3D.castShadow;
    light.receiveShadow = e.object3D.receiveShadow;
    light.position.set(
        e.object3D.position.x,
        e.object3D.position.y,
        e.object3D.position.z,
    );

    addScene(s, e, new Element('light', light.uuid, light));
}

/** 平行光 */
function directionalLight(s: State, e: any) {

    const light = new THREE.DirectionalLight(e.object3D.color);
    light.shadow.camera.far = 1000;
    light.visible = e.object3D.visible;
    light.castShadow = e.object3D.castShadow;
    light.receiveShadow = e.object3D.receiveShadow;
    light.intensity = e.object3D.intensity;
    light.shadow.bias = e.object3D.bias;
    light.position.set(
        e.object3D.position.x,
        e.object3D.position.y,
        e.object3D.position.z,
    );

    addScene(s, e, new Element('light', light.uuid, light));
}

/** 点光源 */
function pointLight(s: State, e: any) {
    const light = new THREE.PointLight(e.object3D.color);
    light.shadow.camera.far = 1000;
    light.visible = e.object3D.visible;
    light.castShadow = e.object3D.castShadow;
    light.receiveShadow = e.object3D.receiveShadow;
    light.intensity = e.object3D.intensity;
    light.power = e.object3D.power;
    light.shadow.bias = e.object3D.bias;
    light.position.set(
        e.object3D.position.x,
        e.object3D.position.y,
        e.object3D.position.z,
    );

    addScene(s, e, new Element('light', light.uuid, light))
}

/** 平面光 */
function rectAreaLight(s: State, e: any) {
    const width = e.object3D.width;
    const height = e.object3D.height;
    const intensity = e.object3D.intensity;
    const light = new THREE.RectAreaLight(e.object3D.color, intensity, width, height);
    light.visible = e.object3D.visible;
    light.castShadow = e.object3D.castShadow;
    light.receiveShadow = e.object3D.receiveShadow;
    light.position.set(
        e.object3D.position.x,
        e.object3D.position.y,
        e.object3D.position.z,
    );
    light.rotation.set(
        e.object3D.rotation.x,
        e.object3D.rotation.y,
        e.object3D.rotation.z,
    );

    addScene(s, e, new Element('light', light.uuid, light));
}

/** 添加到舞台 */
function addScene(s: State, e: any, element: Element<any, any>) {
    const o3d = element.getObject3D();

    element.name = e.name;
    element.uuid = e.uuid;
    o3d && s.scene?.add(o3d);
    s.elementMap.set(element.uuid, element);
}